Cut down allocations in Display impls
authorAlex Crichton <alex@alexcrichton.com>
Fri, 2 Jun 2017 14:21:50 +0000 (07:21 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Mon, 5 Jun 2017 14:36:44 +0000 (07:36 -0700)
Avoid unnecessary `String` allocations in hot paths that get run a lot for large
graphs.

src/cargo/core/package_id.rs
src/cargo/core/resolver/encode.rs
src/cargo/core/source.rs
src/cargo/sources/git/source.rs

index 1e906d97d1613e10f4fd82ec741436019e0cd3e2..4058eeaacc4aea3510e1ebdbc0dbc166d2367ec7 100644 (file)
@@ -28,10 +28,10 @@ impl ser::Serialize for PackageId {
     fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
         where S: ser::Serializer
     {
-        let source = self.inner.source_id.to_url();
-        let encoded = format!("{} {} ({})", self.inner.name, self.inner.version,
-                              source);
-        encoded.serialize(s)
+        s.collect_str(&format_args!("{} {} ({})",
+                                    self.inner.name,
+                                    self.inner.version,
+                                    self.inner.source_id.to_url()))
     }
 }
 
index 403c01e51c45f888089ebdc1ac8c71516f6a540b..3a93c204706fa947b1dd3ab0f9d7e772c3ca0278 100644 (file)
@@ -267,7 +267,7 @@ impl ser::Serialize for EncodablePackageId {
     fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
         where S: ser::Serializer,
     {
-        self.to_string().serialize(s)
+        s.collect_str(self)
     }
 }
 
index 9f32d692dfed261477ceed5660f25790f39a8915..e7a3ce4a2e84bc6f7cdfb7922ce9520570443466 100644 (file)
@@ -173,34 +173,8 @@ impl SourceId {
         }
     }
 
-    pub fn to_url(&self) -> String {
-        match *self.inner {
-            SourceIdInner { kind: Kind::Path, ref url, .. } => {
-                format!("path+{}", url)
-            }
-            SourceIdInner {
-                kind: Kind::Git(ref reference), ref url, ref precise, ..
-            } => {
-                let ref_str = reference.url_ref();
-
-                let precise_str = if precise.is_some() {
-                    format!("#{}", precise.as_ref().unwrap())
-                } else {
-                    "".to_string()
-                };
-
-                format!("git+{}{}{}", url, ref_str, precise_str)
-            }
-            SourceIdInner { kind: Kind::Registry, ref url, .. } => {
-                format!("registry+{}", url)
-            }
-            SourceIdInner { kind: Kind::LocalRegistry, ref url, .. } => {
-                format!("local-registry+{}", url)
-            }
-            SourceIdInner { kind: Kind::Directory, ref url, .. } => {
-                format!("directory+{}", url)
-            }
-        }
+    pub fn to_url(&self) -> SourceIdToUrl {
+        SourceIdToUrl { inner: &*self.inner }
     }
 
     // Pass absolute path
@@ -350,7 +324,7 @@ impl ser::Serialize for SourceId {
         if self.is_path() {
             None::<String>.serialize(s)
         } else {
-            Some(self.to_url()).serialize(s)
+            s.collect_str(&self.to_url())
         }
     }
 }
@@ -372,7 +346,10 @@ impl fmt::Display for SourceId {
             }
             SourceIdInner { kind: Kind::Git(ref reference), ref url,
                             ref precise, .. } => {
-                write!(f, "{}{}", url, reference.url_ref())?;
+                write!(f, "{}", url)?;
+                if let Some(pretty) = reference.pretty_ref() {
+                    write!(f, "?{}", pretty)?;
+                }
 
                 if let Some(ref s) = *precise {
                     let len = cmp::min(s.len(), 8);
@@ -452,25 +429,60 @@ impl hash::Hash for SourceId {
     }
 }
 
-impl GitReference {
-    pub fn to_ref_string(&self) -> Option<String> {
-        match *self {
-            GitReference::Branch(ref s) => {
-                if *s == "master" {
-                    None
-                } else {
-                    Some(format!("branch={}", s))
+pub struct SourceIdToUrl<'a> {
+    inner: &'a SourceIdInner,
+}
+
+impl<'a> fmt::Display for SourceIdToUrl<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self.inner {
+            SourceIdInner { kind: Kind::Path, ref url, .. } => {
+                write!(f, "path+{}", url)
+            }
+            SourceIdInner {
+                kind: Kind::Git(ref reference), ref url, ref precise, ..
+            } => {
+                write!(f, "git+{}", url)?;
+                if let Some(pretty) = reference.pretty_ref() {
+                    write!(f, "?{}", pretty)?;
+                }
+                if let Some(precise) = precise.as_ref() {
+                    write!(f, "#{}", precise)?;
                 }
+                Ok(())
+            }
+            SourceIdInner { kind: Kind::Registry, ref url, .. } => {
+                write!(f, "registry+{}", url)
+            }
+            SourceIdInner { kind: Kind::LocalRegistry, ref url, .. } => {
+                write!(f, "local-registry+{}", url)
+            }
+            SourceIdInner { kind: Kind::Directory, ref url, .. } => {
+                write!(f, "directory+{}", url)
             }
-            GitReference::Tag(ref s) => Some(format!("tag={}", s)),
-            GitReference::Rev(ref s) => Some(format!("rev={}", s)),
         }
     }
+}
 
-    fn url_ref(&self) -> String {
-        match self.to_ref_string() {
-            None => "".to_string(),
-            Some(s) => format!("?{}", s),
+impl GitReference {
+    pub fn pretty_ref(&self) -> Option<PrettyRef> {
+        match *self {
+            GitReference::Branch(ref s) if *s == "master" => None,
+            _ => Some(PrettyRef { inner: self }),
+        }
+    }
+}
+
+pub struct PrettyRef<'a> {
+    inner: &'a GitReference,
+}
+
+impl<'a> fmt::Display for PrettyRef<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self.inner {
+            GitReference::Branch(ref b) => write!(f, "branch={}", b),
+            GitReference::Tag(ref s) => write!(f, "tag={}", s),
+            GitReference::Rev(ref s) => write!(f, "rev={}", s),
         }
     }
 }
index 4a3f8f6f66d893595207e8cf2d43efbf60f670e5..75c0281a4d31abf694f9e8e52dd1de79f18fca46 100644 (file)
@@ -107,7 +107,7 @@ impl<'cfg> Debug for GitSource<'cfg> {
     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
         write!(f, "git repo at {}", self.remote.url())?;
 
-        match self.reference.to_ref_string() {
+        match self.reference.pretty_ref() {
             Some(s) => write!(f, " ({})", s),
             None => Ok(())
         }